﻿using System;

/// <summary>
/// Utility class containing helper functions for measuring timeout 
/// </summary>
public class TimeoutHelper
{
    private TimeSpan timeout;
    private DateTime creationTime;
    private Boolean isInfinite;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="timeout"></param>
    public TimeoutHelper(TimeSpan timeout)
    {
        this.creationTime = DateTime.Now;
        this.timeout = timeout;
        if (timeout.Equals(Infinite)) this.isInfinite = true;
    }

    /// <summary>
    /// Value of infinite timespan
    /// </summary>
    public static TimeSpan Infinite
    {
        get { return TimeSpan.MaxValue; }
    }

    /// <summary>
    /// Value indicating remaining timeout
    /// </summary>
    public TimeSpan RemainingTimeout
    {
        get
        {
            if (this.isInfinite)
                return Infinite;
            return this.timeout.Subtract(DateTime.Now.Subtract(this.creationTime));
        }
    }

    /// <summary>
    /// Get remaining timeout value and throw an exception if the timeout
    /// has expired.
    /// </summary>
    /// <param name="exceptionMessage"></param>
    /// <returns></returns>
    public TimeSpan GetRemainingTimeoutAndThrowIfExpired(String exceptionMessage)
    {
        if (this.isInfinite) return Infinite;
        if (RemainingTimeout < TimeSpan.Zero)
            throw new TimeoutException(exceptionMessage);

        return RemainingTimeout;
    }

    /// <summary>
    /// Throw an exception if the timeout has expired.
    /// </summary>
    /// <param name="exceptionMessage"></param>
    public void ThrowIfTimeoutExpired(String exceptionMessage)
    {
        if (RemainingTimeout < TimeSpan.Zero)
            throw new TimeoutException(exceptionMessage);
    }

    /// <summary>
    /// Value indicating whether timeout has expired.
    /// </summary>
    public Boolean IsExpired
    {
        get
        {
            if (this.isInfinite)
                return false;
            return RemainingTimeout < TimeSpan.Zero;
        }
    }
}